package server;

import server.whiteboard.WhiteBoardRequestThread;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;


public class Server {

    private ServerSocket serverSocket;
    private DatagramSocket datagramSocket;

    private ThreadPoolExecutor threadPoolExecutor;

    /**
     * 初始化线程池
     */
    private void initThreadPool() {
        int corePoolSize = 50;//核心线程数
        int maximumPoolSize = 200;//最大大小，当线程池满时执行拒绝策略
        long keepAliveTime = 100L;//空闲的非核心线程最大存活时间
        TimeUnit unit = TimeUnit.SECONDS;//单位，秒
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);//等待队列，核心线程全部繁忙时进入等待队列，队满时则创建新的线程
        ThreadFactory threadFactory = Executors.defaultThreadFactory();//线程工厂,默认的
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();//拒绝策略

        this.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
    }

    /**
     * 开启端口监听
     * @param port 端口
     */
    public void listen(int port){
        try{
            initThreadPool();
            datagramSocket = new DatagramSocket(port);
            new Thread(() -> {
                while (true) {
                    this.acceptUdp();
                }
            }).start();
            serverSocket = new ServerSocket(port);
            while(true) {
                this.acceptTcp();
            }
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 接收客户端连接请求
     */
    private void acceptTcp() throws IOException {
        //接收客户端的连接
        Socket clientSocket = serverSocket.accept();
        clientSocket.setSoTimeout(3600*1000);
        //每个客户端对应一个线程
        ClientSocketHandleThread clientSocketHandleThread = new ClientSocketHandleThread(clientSocket);
        //在线程池中去执行
        threadPoolExecutor.execute(clientSocketHandleThread);
    }

    /**
     * 接收白板数据请求
     */
    private void acceptUdp() {
        try {
            //报文过大的问题，可以通过控制报文大小来解决，使得每个报文的长度小于MTU。以太网的MTU通常是1500 bytes，
            //其他一些诸如拨号连接的网络MTU值为1280 bytes，如果使用speaking这样很难得到MTU的网络，那么最好将报文长度控制在1280 bytes以下。
            DatagramPacket datagramPacket = new DatagramPacket(new byte[1024], 1024);
            datagramSocket.receive(datagramPacket); // 接收数据
            WhiteBoardRequestThread whiteBoardRequestThread = new WhiteBoardRequestThread(datagramSocket, datagramPacket);
            //在线程池中去执行
            threadPoolExecutor.execute(whiteBoardRequestThread);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
